import threading
import time
import socket
import webbrowser
import cv2
import logging
import numpy as np
import simplejpeg #确保已安装: pip install simplejpeg
from queue import Queue, Full, Empty
from flask import Flask, render_template, Response, jsonify, render_template_string # <--- 修改这里
from werkzeug.serving import make_server

class ImageStreamer:
    def __init__(self, host='0.0.0.0', port=5000, auto_open=True, jpeg_quality=80):


        logging.getLogger('werkzeug').setLevel(logging.ERROR)
        logging.getLogger('werkzeug').disabled = True

        self.app = Flask(__name__,template_folder='/home/sunrise/python_project1/templates')
        # self.app.logger.disabled = True
    
        self.host = host
        self.port = port
        self.auto_open = auto_open
        self.jpeg_quality = jpeg_quality

        self.capture_queue = Queue(maxsize=5)
        self.encode_queue  = Queue(maxsize=5)

        self.latest_data = {}
        self._data_lock = threading.Lock()

        self.running = False
        self.browser_opened = False
        self._encoder_thread = None
        self._flask_thread = None

        self._setup_routes()

    def _setup_routes(self):
        @self.app.route('/')
        def index():
            # 使用 render_template
            return render_template("index.html") # <--- 修改这里

        @self.app.route('/video_feed')
        def video_feed():
            return Response(self._generate_frames_for_stream(),
                            mimetype='multipart/x-mixed-replace; boundary=frame')

        @self.app.route('/data')
        def get_data():
            with self._data_lock:
                data_to_send = self.latest_data.copy()
            return jsonify(data_to_send)

    def _start_encoder_thread(self):
        def _encode_loop():
            print("编码线程已启动。等待来自 capture_queue 的帧...")
            while self.running:
                try:
                    frame = self.capture_queue.get(timeout=0.1)
                except Empty:
                    time.sleep(0.005)
                    continue
                except Exception as e:
                    if self.running:
                        print(f"从 capture_queue 获取帧时出错: {e}")
                    continue
                
                try:
                    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    jpeg_bytes = simplejpeg.encode_jpeg(rgb, quality=self.jpeg_quality,
                                                        colorspace='RGB', fastdct=True)
                    try:
                        self.encode_queue.put(jpeg_bytes, block=False)
                    except Full:
                        try:
                            self.encode_queue.get_nowait()
                            self.encode_queue.put_nowait(jpeg_bytes)
                        except Empty: pass
                        except Full:
                            # print("编码队列已满，丢弃帧")
                            pass
                except Exception as e:
                    if self.running:
                        print(f"JPEG 编码或入队时出错: {e}")
            print("编码线程已停止。")

        if self._encoder_thread is None or not self._encoder_thread.is_alive():
            self._encoder_thread = threading.Thread(target=_encode_loop, daemon=True)
            self._encoder_thread.start()

    def _generate_frames_for_stream(self):
        print("客户端已连接到视频流。")
        frames_streamed = 0
        while self.running:
            try:
                jpeg = self.encode_queue.get(timeout=1.0)
                frames_streamed +=1
                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + jpeg + b'\r\n')
            except Empty:
                if not self.running:
                    break
                continue
            except Exception as e:
                if self.running:
                    print(f"生成帧流时出错: {e}")
                break
        print(f"客户端已从视频流断开。共发送 {frames_streamed} 帧。")

    def update_image_frame(self, frame: np.ndarray):
        if not self.running:
            return
        try:
            self.capture_queue.put(frame, block=False)
        except Full:
            try:
                self.capture_queue.get_nowait()
                self.capture_queue.put_nowait(frame)
            except Empty: pass
            except Full:
                # print("捕获队列已满，丢弃新帧。")
                pass
        except Exception as e:
            if self.running:
                print(f"将帧放入 capture_queue 时出错: {e}")

    def update_data(self, data_dict: dict):
        if not self.running:
            return
        with self._data_lock:
            self.latest_data = data_dict.copy()

    def start(self):
        if self.running:
            print("服务器已在运行。")
            return
        self.running = True

        print("正在启动编码器线程...")
        self._start_encoder_thread()

        print("正在启动 Flask 服务器...")
        self._flask_thread = threading.Thread(target=lambda: self.app.run(
            host=self.host, port=self.port, debug=False, threaded=True, use_reloader=False), daemon=True)
        self._flask_thread.start()

        self._wait_for_server()

        if self.auto_open and not self.browser_opened:
            url = f'http://localhost:{self.port}'
            print(f"尝试在 {url} 打开浏览器")
            threading.Thread(target=lambda: webbrowser.open(url), daemon=True).start()
            self.browser_opened = True
        
        print(f'ImageStreamer 服务器已在 http://{self.host if self.host!="0.0.0.0" else "localhost"}:{self.port} 启动')

    def _wait_for_server(self, timeout_seconds=10):
        print("正在等待 Flask 服务器启动...")
        start_time = time.time()
        while time.time() - start_time < timeout_seconds:
            try:
                with socket.create_connection(('localhost', self.port), timeout=0.2):
                    print("Flask 服务器已启动。")
                    return
            except (socket.error, ConnectionRefusedError):
                time.sleep(0.2)
        print(f"Flask 服务器未在 {timeout_seconds} 秒内启动。")

    def stop(self):
        if not self.running:
            print("服务器尚未运行。")
            return
            
        print("正在停止 ImageStreamer 服务器...")
        self.running = False

        time.sleep(0.2)

        for q in [self.capture_queue, self.encode_queue]:
            while not q.empty():
                try: q.get_nowait()
                except Empty: break
            
        if self._encoder_thread and self._encoder_thread.is_alive():
            print("正在等待编码器线程完成...")
            self._encoder_thread.join(timeout=2) 
            if self._encoder_thread.is_alive():
                print("编码器线程未及时完成。")
        
        print("ImageStreamer 服务器已停止。")

        # 重置浏览器打开状态，下次 start() 时会重新打开
        self.browser_opened = False
        

# --- 示例用法 ---
# if __name__ == '__main__':
#     streamer = ImageStreamer(port=5001, auto_open=True, jpeg_quality=75)
#     streamer.start()
    
#     cap = cv2.VideoCapture(0)
#     if not cap.isOpened():
#         print("错误：无法打开来自摄像头0的视频流。")
#         streamer.stop()
#         exit()
    
#     print("摄像头已打开。正在流式传输帧...")
#     frame_id = 0
#     try:
#         while streamer.running:
#             ret, cv_frame = cap.read()
#             if not ret:
#                 print("无法从摄像头抓取帧，正在重试...")
#                 time.sleep(0.1)
#                 cap.release()
#                 cap = cv2.VideoCapture(0)
#                 if not cap.isOpened():
#                     print("无法重新打开摄像头。正在停止。")
#                     break
#                 continue

#             streamer.update_image_frame(cv_frame)
#             frame_id += 1

#             current_time_str = time.strftime("%Y-%m-%d %H:%M:%S")
#             example_data = {
#                 "timestamp": current_time_str,
#                 "frame_id": frame_id,
#                 "source": "webcam_0",
#                 "status_message": "Streaming live",
#                 "capture_q_size": streamer.capture_queue.qsize(),
#                 "encode_q_size": streamer.encode_queue.qsize(),
#                 "custom_value": np.random.random()
#             }
#             streamer.update_data(example_data)

#             time.sleep(1/30)
            
#     except KeyboardInterrupt:
#         print("收到键盘中断。")
#     finally:
#         print("正在清理...")
#         if cap.isOpened():
#             cap.release()
#         streamer.stop()
#         print("程序完成。")